﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Commands;
using ImageConverter.Configuration;
using ImageConverter.Model;
using ImageConverter.Model.Enums;
using ImageConverter.Utils;
using ImageConverter.ViewModels;

namespace ImageConverter
{
    public class ViewModel : ViewModelBase, IViewModel
    {
        public const int BaseLength = 2048;

        public ViewModel()
        {
            BrowseDirCommand = new DelegateCommand<object>(OnBrowseDirCommand);
            BrowseOutputDirCommand = new DelegateCommand<object>(OnBrowseOutputDirCommand);
            RefreshContainerListCommand = new DelegateCommand<object>(OnRefreshContainerListCommand);
            RecodeContainersCommand = new DelegateCommand<object>(OnRecodeContainersCommand);

            ContainerTypesList = new List<ContainerTypeEnum>(
                Enum.GetValues(typeof(ContainerTypeEnum)).Cast<ContainerTypeEnum>()
                );
            ContainerFactory = new EntryContainerFactory();
            ContainerLocator = new EntryContainerLocator();
        }

        #region IViewModel Members

        public ObservableCollection<ContainerItem> Containers
        {
            get
            {
                return containers;
            }
            private set
            {
                containers = value;
                NotifyOfPropertyChange(() => Containers);
            }
        }

        public ContainerItem SelectedContainer
        {
            get
            {
                return selectedContainer;
            }
            set
            {
                selectedContainer = value;
                NotifyOfPropertyChange(() => SelectedContainer);
            }
        }

        public string InputPath
        {
            get
            {
                return inputPath;
            }
            set
            {
                inputPath = value;
                NotifyOfPropertyChange(() => InputPath);
            }
        }

        public string OutputPath
        {
            get
            {
                return outputPath;
            }
            set
            {
                outputPath = value;
                NotifyOfPropertyChange(() => OutputPath);
            }
        }

        public ContainerTypeEnum ContainerType
        {
            get
            {
                return containerType;
            }
            set
            {
                containerType = value;
                NotifyOfPropertyChange(() => ContainerType);
                OnContainerTypeChanged(value);
            }
        }

        public IEnumerable<ContainerTypeEnum> ContainerTypesList
        {
            get
            {
                return containerTypesList;
            }
            private set
            {
                containerTypesList = value;
                NotifyOfPropertyChange(() => ContainerTypesList);
            }
        }

        public bool IsMainWindowMinimized
        {
            get
            {
                return isMainWindowMinimized;
            }
            private set
            {
                isMainWindowMinimized = value;
                NotifyOfPropertyChange(() => IsMainWindowMinimized);
            }
        }

        public bool CompressOutput
        {
            get
            {
                return compressOutput;
            }
            set
            {
                compressOutput = value;
                NotifyOfPropertyChange(() => CompressOutput);
            }
        }

        public IEntryContainerFactory ContainerFactory { get; private set; }

        public IEntryContainerLocator ContainerLocator { get; private set; }

        public IConfiguration Configuration { get; private set; }

        public DelegateCommand<object> BrowseDirCommand { get; private set; }

        public DelegateCommand<object> BrowseOutputDirCommand { get; private set; }

        public DelegateCommand<object> SelectedContainerChangedCommand { get; private set; }

        public DelegateCommand<object> RefreshContainerListCommand { get; private set; }

        public DelegateCommand<object> RecodeContainersCommand { get; private set; }

        #endregion

        #region Private methods

        private void OnContainerTypeChanged(ContainerTypeEnum containerType)
        {
            ContainerFactory.SetProductType(containerType);
            ContainerLocator.SetContainerType(containerType);

            OnRefreshContainerListCommand(null);
        }

        private void OnBrowseDirCommand(object parameter)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();

            if (!String.IsNullOrEmpty(InputPath))
                dialog.SelectedPath = InputPath;

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                InputPath = dialog.SelectedPath;
                OutputPath = Path.Combine(InputPath, "out");

                Containers = ContainerLocator.Locate(InputPath).ToObservableCollection();
            }
        }

        private void OnBrowseOutputDirCommand(object parameter)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();

            if (!String.IsNullOrEmpty(OutputPath))
                dialog.SelectedPath = OutputPath;

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                OutputPath = dialog.SelectedPath;
            }
        }

        private void OnRefreshContainerListCommand(object parameter)
        {
            Containers = ContainerLocator.Locate(InputPath).ToObservableCollection();
        }

        private void OnRecodeContainersCommand(object parameter)
        {
            if (!Directory.Exists(OutputPath))
                Directory.CreateDirectory(OutputPath);

            ResetEntriesAndArchives();

            IsMainWindowMinimized = true;

            IRecodeViewModel viewModel = new RecodeViewModel();
            viewModel.BeginRecode(Containers, ContainerFactory, BaseLength, OutputPath, CompressOutput);

            RecodeWindow window = new RecodeWindow(viewModel);
            window.ShowDialog();
        }

        private void ResetEntriesAndArchives()
        {
            foreach (var a in Containers)
            {
                if (a.Entries != null)
                    a.Entries.Clear();
                a.Status = ItemStatusEnum.Unknown;
            }
        }

        #endregion

        #region Private fields

        private ObservableCollection<ContainerItem> containers;
        private ContainerItem selectedContainer;
        private string inputPath;
        private string outputPath;
        private ContainerTypeEnum containerType;
        private IEnumerable<ContainerTypeEnum> containerTypesList;
        private bool isMainWindowMinimized;
        private bool compressOutput;

        #endregion
    }
}
